package waveAlgorithm.control;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

import waveAlgorithm.entity.Process;

/**
 * This class is used to do the initialization.
 * 
 * @since Oct 17, 2011
 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
 * @version $Id: Initiator.java 31 2011-10-30 10:52:55Z zexpp5@gmail.com $
 * 
 */
public class Initiator {
	private static Logger logger = Logger.getLogger(Initiator.class);

	private Initiator() {
	}

	/**
	 * to generate a arbitratry tree with n nodes;
	 * 
	 * @param n
	 * @return
	 * @description
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 30, 2011 8:45:14 AM
	 */
	public static HashMap<String, Process> initRandomly(int n) {
		HashMap<String, Process> processes = creatProcesses(n);
		constructArbitraryStructure(processes, n);
		return processes;
	}

	/**
	 * to init a balanced binary tree
	 * 
	 * @return  
	 * @description   
	 *
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>  
	 * @update Oct 30, 2011 8:56:09 AM
	 */
	public static HashMap<String, Process> initBalancedBinaryTree() {
		HashMap<String, Process> processes = creatProcesses(9);
		constructBalancedBinaryTreeStructure(processes);
		return processes;
	}
	
	/**
	 * to init an unbalanced binary tree
	 * 
	 * @return  
	 * @description   
	 *
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>  
	 * @update Oct 30, 2011 8:56:39 AM
	 */
	public static HashMap<String, Process> initUnBalancedBinaryTree() {
		HashMap<String, Process> processes = creatProcesses(7);
		constructUnbalancedBinaryTreeStructure(processes);
		return processes;
	}
	
	
	
	/**
	 * to create n processes;
	 * 
	 * @param n
	 * @return
	 * @description
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 30, 2011 8:46:08 AM
	 */
	private static HashMap<String, Process> creatProcesses(int n) {
		HashMap<String, Process> processes = new HashMap<String, Process>();
		for (char i = 65; i - 65 < n; i++) {
			processes.put(i + "", new Process(i + ""));
		}

		return processes;
	}

	/**
	 * to construct a arbitratry tree
	 * 
	 * @param processes
	 * @param n
	 * @description
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 30, 2011 8:46:32 AM
	 */
	private static void constructArbitraryStructure(
			HashMap<String, Process> processes, int n) {

		char current = 65;
		for (int numNodeTotal = n, numNodeLeft = n; numNodeLeft > 0; numNodeLeft--, current++) {
			if (numNodeLeft == numNodeTotal) {
				continue;
			} else {
				char parent = (char) (65 + (int) (Math.random() * (numNodeTotal - numNodeLeft)));
				Process currentProcess = processes.get(current + "");
				Process parentProcess = processes.get(parent + "");
				logger.info("     " + parentProcess.getId()
						+ "    got a child     " + currentProcess.getId() + "");
				parentProcess.setNeigh(currentProcess);
				currentProcess.setNeigh(parentProcess);

			}
		}

	}

	/**
	 * to generate a balanced binary tree.
	 * 
	 * @param processes
	 * @description
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 30, 2011 8:50:41 AM
	 */
	private static void constructBalancedBinaryTreeStructure(
			HashMap<String, Process> processes) {
		Process currentProcess = processes.get("B");
		Process parentProcess = processes.get("A");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("C");
		parentProcess = processes.get("A");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("D");
		parentProcess = processes.get("B");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("E");
		parentProcess = processes.get("B");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("F");
		parentProcess = processes.get("C");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("G");
		parentProcess = processes.get("C");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);
		
		currentProcess = processes.get("H");
		parentProcess = processes.get("D");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);
		
		currentProcess = processes.get("I");
		parentProcess = processes.get("D");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

	}

	/**
	 *  to generate an unbalanced binary tree.
	 * 
	 * @param processes  
	 * @description   
	 *
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>  
	 * @update Oct 30, 2011 8:51:54 AM
	 */
	private static void constructUnbalancedBinaryTreeStructure(
			HashMap<String, Process> processes) {
		Process currentProcess = processes.get("B");
		Process parentProcess = processes.get("A");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("C");
		parentProcess = processes.get("A");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("D");
		parentProcess = processes.get("B");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("E");
		parentProcess = processes.get("B");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("F");
		parentProcess = processes.get("D");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);

		currentProcess = processes.get("G");
		parentProcess = processes.get("D");
		parentProcess.setNeigh(currentProcess);
		currentProcess.setNeigh(parentProcess);
	}
}
